﻿//===============================================================================
// Magic OQL
//===============================================================================
// Copyright ?Magic Thought Corporation. All rights reserved.
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE.
//===============================================================================
// Richie (http://www.cnblogs.com/RicCC)
// March 8, 2008
//===============================================================================

using Antlr.Runtime;
using Antlr.Runtime.Tree;

namespace SQLAnalyticLibrary.Expressions
{
    /// <summary>
    /// Select clause
    /// </summary>
    public class Column : Expression
    {
        private Identifier _identifier = null;
        private Constant _constant = null;
        private bool _allColumn = false;
        private Alias _alias = null;

        #region constructors
        public Column(Expression node)
            : base(node)
        {
            Column col = node as Column;
            if (col != null)
            {
                this._alias = col._alias;
                this._allColumn = col._allColumn;
                this._constant = col._constant;
                this._identifier = col._identifier;
            }
        }
        public Column(IToken t)
            : base(t)
        {
            this.Token.Text = string.Empty;
        }
        #endregion

        public override Expression DupNode()
        {
            return new Column(this);
        }
        public override void AddChild(Expression t)
        {
            bool handled = false;
            if (t == null) return;
            if (t._children != null)
            {
                int start =0;
                foreach (Expression exp in t._children)
                {
                    if (start == 0 || exp.TokenStartIndex < start)
                        start = exp.TokenStartIndex;
                    if (!exp.IsNil)
                    {
                        //if (Identifier.IsIdentifier(exp))
                        //{
                        //    this._identifier = exp as Identifier;
                        //    handled = true;
                        //}
                        //else if (exp.Token.Type == OQLParser.MUL)
                        //{
                        //    this._allColumn = true;
                        //    handled = true;
                        //}
                        //else if (Alias.IsAlias(exp))
                        //{
                        //    this._alias = exp as Alias;
                        //    handled = true;
                        //}
                        //else if (exp.Token.Type == OQLParser.DOT)
                        //    handled = true;
                    }
                }
                if (this.TokenStartIndex ==0 || this.TokenStartIndex > start)
                    this.TokenStartIndex = start;
            }
            else if (!t.IsNil && SQLAnalyticLibrary.Expressions.Text.IsText(t) && t.Text == "*")
            {
                this._allColumn = true;
                handled = true;
            }
            else if (string.IsNullOrEmpty(t.Text))
            {
                handled = true;
            }

            int end = GetMaxStopIndex(t);
            if (this.TokenStartIndex > 0 &&　t.TokenStartIndex < this.TokenStartIndex)
                this.TokenStartIndex = t.TokenStartIndex;
            if (end > this.TokenStopIndex)
                this.TokenStopIndex = end;
            if (!t.IsNil)
            {
                if (Identifier.IsIdentifier(t))
                {
                    this._identifier = t as Identifier;
                    handled = true;
                }
                else if (t.Token.Type == OQLParser.MUL)
                {
                    this._allColumn = true;
                    handled = true;
                }
                else if (Alias.IsAlias(t))
                {
                    this._alias = t as Alias;
                    handled = true;
                }
                else if (Constant.IsConstant(t))
                {
                    this._constant = t as Constant;
                    handled = true;
                }
                else if (t.Token.Type == OQLParser.DOT)
                    handled = true;
            }

           
            if (!handled)
                base.InternalAddChild(t);
            
        }

        public bool HasTableName
        {
            get
            {
                return this._identifier != null && this._identifier.HasTableName;
            }
        }
        public string TableName
        {
            get
            {
                if (!this.HasTableName) return null;
                return this._identifier.TableName;
            }
        }
        public bool HasColumnName
        {
            get
            {
                return this._identifier != null && this._identifier.HasColumnName;
            }
        }
        public bool HasConstantName
        {
            get
            {
                return this._constant != null;
            }
        }
        public string ColumnName
        {
            get
            {
                if (this.HasColumnName) 
                    return this._identifier.ColumnName;
                if(this.HasConstantName)
                    return this._constant.Text;
                return null;
            }
        }
        public bool HasAlias
        {
            get
            {
                return this._alias != null;
            }
        }
        public string AliasName
        {
            get
            {
                if (!this.HasAlias) return null;
                return this._alias.Name;
            }
        }
        public bool IsAllColumn
        {
            get
            {
                if (this.IsIdentifier) return this._identifier.IsAllColumn;
                return this._allColumn;
            }
        }
        public bool IsConstant
        {
            get
            {
                //the constant remains in the children list.
                if (this._children == null || this._children.Count <= 0) return false;
                return Constant.IsConstant(this._children[0]);
            }
        }
        public bool IsUserVariable
        {
            get
            {
                //the user variable remains in the children list.
                if (this._children == null || this._children.Count <= 0) return false;
                return UserVariable.IsUserVariable(this._children[0]);
            }
        }
        public bool IsIdentifier
        {
            get
            {
                //if the column is an identifier, the associated child is removed, and the identifier text is stored in the private member _identifier.
                return this._identifier != null;
            }
        }

        public override string ToString()
        {
            System.Text.StringBuilder builder = new System.Text.StringBuilder();
            if (this._identifier != null)
                builder.Append(" ").Append(this._identifier.ToString());
            if (this._constant != null)
                builder.Append(" ").Append(this._constant.ToString());
            if (this._allColumn)
                builder.Append(".*");
            if (this.HasAlias)
                builder.Append(" ").Append(this._alias.ToString());
            return builder.ToString();
        }

        public override void VisitSql(ISqlVisitor visitor)
        {
            if (this.HasTableName) //try to identify table name.
            {
                visitor.Table(this.TableName);
                visitor.Sql(".");
            }
            if (this.IsAllColumn) visitor.Sql("*");
            else if (this.HasColumnName) //try to identify column name.
                visitor.Column(this.TableName, this.ColumnName, true);
            if (this._children != null)
                this.InternalVisitSql(visitor, false, null); //is this column a compsite expression, such as functions?
            if (this.HasAlias)
            {
                visitor.Space();
                this._alias.VisitSql(visitor);
            }
        }

        internal static int TreeType
        {
            get
            {
                return OQLParser.Column;
            }
        }
        public static bool IsColumn(Expression exp)
        {
            if (exp == null || exp.IsNil) return false;
            return exp.Token.Type == OQLParser.Column;
        }
    }
}
